<template>
  <div :id="editorId"
       class="my_editor"
       :class="[{
      '--read-only': readOnly,
    }, editorClass]">
    <div class="my_editor-actions">
      <i class="iconfont icon-fuzhi action-btn"
         title="点击复制"
         @click="copyData"></i>
      <i class="iconfont action-btn"
         :class="isFullScreen ? 'icon-quitquanping-copy' : 'icon-pingmu_quanping'"
         :title="isFullScreen ? '退出全屏' : '全屏模式下编辑或查看'"
         @click="switchFullScreen"></i>
    </div>
  </div>
  <el-dialog v-model="isFullScreen"
             :title="`${fullScreenTitle}${readOnly ? ' ( 只读 )' : ''}`"
             custom-class="node-config-dialog"
             width="80%"
             destroy-on-close>
    <div class="my_editor fullscreen-editor"
         :class="[{
          '--read-only': readOnly,
        }]"
         style="height: 45vh">
      <section style="display: flex; position: relative; text-align: initial; width: 100%; height: 100%;"></section>
    </div>
    <template #footer>
      <div class="footer-modal">
        <el-button @click="closedFullScreenDialog"
                   size="small"
                   class="footer-modal--btn">关闭
        </el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script>
import { computed, defineComponent, nextTick, onMounted, onUnmounted, ref, watch, } from "vue";
import { debounce } from "lodash-es";
import loader from "@monaco-editor/loader";
import { copyText, GenerateID } from "../../../../../utils/utils.js";
import {
  defaultOpts,
  formatDocument,
  handleInputCode,
  registerApiCompletion,
  registerMyDarkTheme,
} from "./editor-config";
import { ElMessage } from "element-plus";

loader.config({
  paths: { vs: "https://unpkg.com/monaco-editor@0.27.0/min/vs" },
});

export default defineComponent({
  name: "MyMonacoEditor",
  props: {
    language: {
      type: String,
      default: "plaintext",
    },
    code: {
      type: [String, Array, Object],
      default: "",
    },
    readOnly: Boolean,
    useMinimap: Boolean,
    lineNumbers: {
      type: String,
      default: "on",
    },
    wordWrap: {
      type: String,
      default: "on",
    },
    autoFormat: Boolean,
    options: {
      type: Object,
      default: () => {
      },
    },
    completions: Array,
    extra: Object,
    height: {
      type: Number,
      default: 240,
    },
    editorClass: String,
    fullScreenTitle: {
      type: String,
      default: "全屏模式",
    },
  },
  emits: ["change", "blur"],
  // components: { NModal, NCard, NButton },
  setup(props, ctx) {
    const editorId = computed(() => `my_editor-${GenerateID()}`);
    let monaco = null;
    let editor = null;
    let fullEditor = null;
    const themeName = "dark-theme";

    const isFullScreen = ref(false);

    const copyData = () => {
      if (editor) {
        copyText(editor.getValue());
        ElMessage({
          type: "success",
          message: "复制成功",
        });
      }
    };

    const changeHandler = () => {
      if (editor) {
        const value = editor.getValue();
        ctx.emit("change", {
          value,
          extra: props.extra,
        });
      }
    };
    const blurHandler = () => {
      if (editor) {
        const value = editor.getValue();
        ctx.emit("blur", {
          value,
          extra: props.extra,
        });
        if (props.autoFormat) {
          formatDocument(editor, props.language);
        }
      }
    };

    const debounceChangeHandler = debounce(changeHandler, 300);

    const switchFullScreen = () => {
      isFullScreen.value = !isFullScreen.value;
      nextTick(() => {
        if (isFullScreen.value) {
          openedFullScreenDialog();
        } else {
          closedFullScreenDialog();
        }
      });
    };

    const openedFullScreenDialog = () => {
      const dom = document.querySelector(".fullscreen-editor > section");
      if (dom) {
        const opts = Object.assign({}, defaultOpts, props.options, {
          tabSize: 2,
          value: "",
          language: props.language,
          theme: themeName,
          readOnly: props.readOnly,
          minimap: {
            enabled: props.useMinimap,
          },
          lineNumbers: props.lineNumbers,
          wordWrap: props.wordWrap,
        });
        const ce = monaco.editor.create(dom, opts);

        ce.setValue(editor.getValue());
        if (props.autoFormat) {
          formatDocument(ce, props.language);
        }

        ce.onDidChangeModelContent(() => debounceChangeHandler());
        ce.onDidBlurEditorText(() => blurHandler());

        fullEditor = ce;
      }
    };

    const closedFullScreenDialog = () => {
      if (fullEditor) {
        if (editor && !props.readOnly) {
          editor.setValue(fullEditor.getValue());
          editor.focus();
        }

        fullEditor.dispose();
      }
      isFullScreen.value = false;
    };

    watch(
        () => props.code,
        (nv) => {
          if (editor) {
            const inputCode = handleInputCode(props.language, nv);
            editor.setValue(inputCode);
            formatDocument(editor, props.language);
          }
        }
    );

    onMounted(async () => {
      monaco = await loader.init();

      registerMyDarkTheme(monaco);
      registerApiCompletion(monaco, props.language, props.completions);

      await nextTick();

      const dom = document.getElementById(editorId.value);
      if (dom) {
        const opts = Object.assign({}, defaultOpts, props.options, {
          tabSize: 2,
          value: "",
          language: props.language,
          theme: themeName,
          readOnly: props.readOnly,
          minimap: {
            enabled: props.useMinimap,
          },
          lineNumbers: props.lineNumbers,
          wordWrap: props.wordWrap,
        });
        const ce = monaco.editor.create(dom, opts);

        const inputCode = handleInputCode(props.language, props.code);
        ce.setValue(inputCode);
        if (props.autoFormat) {
          formatDocument(ce, props.language);
        }

        if (props.height > 0) {
          dom.style.height = `${props.height}px`;
        }

        ce.onDidChangeModelContent(() => debounceChangeHandler());
        ce.onDidBlurEditorText(() => blurHandler());

        editor = ce;
      }
    });

    onUnmounted(() => {
      editor?.dispose();
      fullEditor?.dispose();
    });

    return {
      editorId,
      isFullScreen,
      copyData,
      switchFullScreen,
      openedFullScreenDialog,
      closedFullScreenDialog,
    };
  },
});
</script>
<style lang="less">
.fullscreen-editor-wp {
  width: 90%;

  .n-card-header {
    padding: 16px 20px 8px 20px;

    .n-card-header__main {
      color: #2681ff;
      font-size: 14px;
      font-weight: 500;
    }
  }
}
</style>
